/**************************************************************************
 *
 * Copyright (c) 2002 - 2011 by Computer Architecture Department,
 * Universitat Politecnica de Catalunya.
 * All rights reserved.
 *
 * The contents of this file may not be disclosed to third parties,
 * copied or duplicated in any form, in whole or in part, without the
 * prior permission of the authors, Computer Architecture Department
 * and Universitat Politecnica de Catalunya.
 *
 */

////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "stdafx.h"
#include "Config/GeneratorConfiguration.hpp"

////////////////////////////////////////////////////////////////////////////////

namespace dxcodegen
{
  namespace Config
  {
    class GeneratorConfiguration;
  }
  
  namespace Items
  {
    class ClassDescription;
    class MethodDescription;
  }

  namespace Parser
  {
      class DXHParser;
  }

  namespace Generator
  {

    /******************************************************
    Additional info needed for generate a method to be used
    with methodDescription by PerMethodGenerator
    ******************************************************/
    struct ExtendedMethodDescription {
        int CID;
        std::string ClassName;
        bool autogenerate;   // Include autogenerated code
        ExtendedMethodDescription ():
            CID(0), autogenerate(false) {}
    };
 
    /****************************************
      Generate code for an individual parameter
    ****************************************/
    class PerParameterGenerator {
    public:
        /***********************************
        Generates code for fitting it before the call.
        ***********************************/
        void generateCodeBeforeCall(std::ofstream *out);

        /****************************************
        Generates code for fitting it as an argument of the call
        ******************************************/
        void generateCodeForCall(std::ofstream *out);

        /****************************************
        Generates code for fitting it after the call.
        ****************************************/
        void generateCodeAfterCall(std::ofstream *out);

        /***************************************
        Accessors
        ***************************************/
        void setParameter(Items::MethodDescriptionParam p);
    private:
        Items::MethodDescriptionParam param;

        // Classification of parameters
        // each type need different code generation
        enum ParameterType {                     // Examples:
            VALUE_PARAMETER,                     // UINT
            VALUE_POINTER_PARAMETER,             // Rect *
            INTERFACE_POINTER_PARAMETER,         // IDirect3DDevice9 *
            POINTER_INTERFACE_POINTER_PARAMETER, // IDirect3DDevice9 **
        };

        // Calculates the type of the parameter
        ParameterType getType();

        std::string removeLastAsterisk(std::string);

        // Remove CONST string from parameter type
        std::string removeConst(std::string);

        // Translate REFGUID and REFIID to GUID
        std::string translateReferencesToGuid(std::string);

        // Some pointer parameters that doesn't follow general rules
        // ( i. e. D3DVERTEXELEMENT9 * in IDirect3DDevice9::CreateVertexDeclaration )
        // don't have the structure dumped after the pointer. We will treat those as
        // value parameters.
        bool isIrregularPointer(std::string s);

    };

    /****************************************
      Generate code for an individual method
    ****************************************/
    class PerMethodGenerator {
    public:
        /***************************************
        Output declaration of the method.
        ***************************************/
        void generateDeclaration(std::ofstream *out);

        /***************************************
        Output definition of the method.
        ***************************************/
        void generateDefinition(std::ofstream *out);

        /***************************************
        Output switch branch of the method.
        ***************************************/
        void generateSwitchBranch(std::ofstream *out);

        /***************************************
        Output enum field of the method.
        ***************************************/
        void generateEnumField(std::ofstream *out);

        /****************************************
        Sets info about the method
        ****************************************/
        void setMethodInfo( Items::MethodDescription &md,
            ExtendedMethodDescription &exmd);

     private:
         Items::ClassDescription methodClass;
         Items::MethodDescription method;
         ExtendedMethodDescription exMethod;
         std::string composeMethodName();
         std::string composeFieldName();

         PerParameterGenerator perParameterGenerator;
     };

    class D3D9PixRunPlayerGenerator : public IGenerator
    {
    public:

      /*******************
      Accessors
      *******************/
      void setClasses(std::vector<Items::ClassDescription> &c);

      
      /*******************
      Generates .gen files

      Pre: initialize()
      ********************/
      void GenerateCode();

      D3D9PixRunPlayerGenerator(Config::GeneratorConfiguration &_configuration):
      configuration(_configuration) {}

    private:

        std::map< std::pair< std::string, std::string >, int > nameToCID;
        std::map< int, ExtendedMethodDescription > extendedMethodDescriptions;
        std::vector<Items::ClassDescription> classes;
        PerMethodGenerator perMethodGenerator;
        Config::GeneratorConfiguration &configuration;

        /***********************************************
        When classes are set some initialization is needed.
        ************************************************/
        void onSetClasses();


    };
  }
}

////////////////////////////////////////////////////////////////////////////////
